/***************************************************************************//**
 * @file oled
 * @brief Oled application code
 *******************************************************************************
 * # License
 * <b>Copyright 2022 Silicon Laboratories Inc. www.silabs.com</b>
 *******************************************************************************
 *
 * SPDX-License-Identifier: Zlib
 *
 * The licensor of this software is Silicon Laboratories Inc.
 *
 * This software is provided \'as-is\', without any express or implied
 * warranty. In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 *
 *******************************************************************************
 * # Experimental Quality
 * This code has not been formally tested and is provided as-is. It is not
 * suitable for production environments. In addition, this code will not be
 * maintained and there may be no bug maintenance planned for these resources.
 * Silicon Labs may update projects from time to time.
 ******************************************************************************/
#include <string.h>
#include <stdio.h>
#include "sl_bluetooth.h"
#include "sl_sleeptimer.h"
#include "app.h"
#include "micro_oled_ssd1306.h"
#include "glib.h"
#include "oled.h"
#include "glib_font.h"
#include "sl_i2cspm_instances.h"
#include "app_log.h"

typedef struct glib_display{
  /** Max number digit */
  uint8_t index[5];
} glib_display_t;

// -----------------------------------------------------------------------------
// Private variables

/* This array is generated by GIMP Tool. A image with bitmap format can
 * use this tool to convert to code.
 * To draw an image or custom bitmaps on the oled, the glib_draw_bmp()
 * function can be used.
 * */
static const unsigned char silicon_labs_logo_64x23[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
  0x00, 0x00, 0x00, 0x80, 0xff, 0x1f, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xf0,
  0xff, 0x7f, 0x00, 0x3e, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0x7f,
  0x00, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x80, 0x7f, 0x00, 0x06, 0x80, 0xff,
  0xff, 0xff, 0xe0, 0xff, 0x80, 0x03, 0xc0, 0xff, 0x01, 0xf8, 0xff, 0x7f,
  0xe0, 0x01, 0xc0, 0x03, 0x00, 0x00, 0xfe, 0x7f, 0xf0, 0x01, 0x00, 0x01,
  0x00, 0x00, 0xf8, 0x3f, 0xf8, 0x03, 0x00, 0xf0, 0x07, 0x00, 0xe0, 0x3f,
  0xfc, 0x03, 0x00, 0x00, 0x20, 0x00, 0xe0, 0x1f, 0xfe, 0x0f, 0x00, 0x00,
  0xc0, 0x00, 0xe0, 0x07, 0xfe, 0xff, 0x00, 0x00, 0xfc, 0x00, 0xe0, 0x03,
  0xff, 0xc3, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x00, 0x7e, 0x00, 0xfe, 0xff,
  0x7f, 0x00, 0x38, 0x00, 0x3e, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x0c, 0x00,
  0x1c, 0x80, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x18, 0x00, 0xff, 0xff,
  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00
};

static glib_context_t glib_context;

// -----------------------------------------------------------------------------
// Public function definitions

/***************************************************************************//**
 * Initialize the OLED display.
 ******************************************************************************/
void oled_app_init(void)
{
  if (ssd1306_init(sl_i2cspm_qwiic) == SL_STATUS_OK) {
    app_log("[OLED]: SparkFun Oled intialized success.\r\n");
  } else {
    app_log("[OLED]: SparkFun Oled initialized failed!\r\n");
  }

  /* Initialize the display */
  glib_init(&glib_context);

  glib_context.bg_color = GLIB_BLACK;
  glib_context.text_color = GLIB_WHITE;

  /* Fill lcd with background color */
  glib_clear(&glib_context);

  glib_draw_xbitmap(&glib_context,
                    0, 10, silicon_labs_logo_64x23,
                    64, 23, GLIB_WHITE);
  glib_update_display();
  sl_sleeptimer_delay_millisecond(1000);

  /* Fill lcd with background color */
  glib_clear(&glib_context);

  /* Use Narrow font */
  glib_set_font(&glib_context, NULL);
  glib_draw_string(&glib_context, "PEOPLE", 15, 0);

  glib_draw_line(&glib_context, 0, 11, 63, 11, GLIB_WHITE);

  glib_draw_string(&glib_context, " ", 0, 20);

  glib_draw_line(&glib_context, 0, 35, 63, 35, GLIB_WHITE);
  glib_update_display();
}

/***************************************************************************//**
 * Show the number of people count and people entered the room so far on the
 * OLED display
 ******************************************************************************/
void oled_show_people_count(uint32_t people_count,
                            uint32_t people_entered_so_far)
{
  char number_str[9];
  char tmp[11];
  int n;
  glib_status_t status;

  // To keep the people count number in the middle of the screen
  n = snprintf(number_str, sizeof(number_str), "%lu", people_count);
#define LINE_MAX_CHAR (10)
  if (n < LINE_MAX_CHAR) {
    const char blank[] = "         ";
    int n_blank = (LINE_MAX_CHAR - n) / 2;
    snprintf(tmp, sizeof(tmp), "%.*s%s%.*s", n_blank, blank,
             number_str,
             LINE_MAX_CHAR - n - n_blank,
             blank);
    glib_draw_string(&glib_context, tmp, 0, 20);
  } else {
    glib_draw_string(&glib_context, number_str, 0, 20);
  }

  // TODO: screen only able to display 0-999
  n = snprintf(tmp, sizeof(tmp), "SO FAR:%lu", people_entered_so_far);
  glib_draw_string(&glib_context, tmp, 0, 39);

  status = glib_update_display();
  if (GLIB_OK != status) {
    app_log("[OLED]: glib_update_display() error: %d\r\n", (int)status);
    return;
  }
}
